package cn.wanda.bi.sunshine.platform.server.utils;

import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;

import java.beans.BeanInfo;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.lang.reflect.Method;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

/**
 * Created by wangfupeng1
 */
public class MapUtil {

    public static final Logger logger = LoggerFactory.getLogger(MapUtil.class);

    public static <T> Map objToMap(T obj) {
        if (obj == null) return null;

        Map<String, Object> map = new HashMap<>();
        BeanInfo beanInfo = null;
        try {
            beanInfo = Introspector.getBeanInfo(obj.getClass());
            PropertyDescriptor[] propertyDescriptors = beanInfo.getPropertyDescriptors();
            for (PropertyDescriptor property : propertyDescriptors) {
                String key = property.getName();
                if (key.compareToIgnoreCase("class") == 0) {
                    continue;
                }
                Method getter = property.getReadMethod();
                Object value = getter != null ? getter.invoke(obj) : null;
                map.put(key, value);
            }
        } catch (Exception e) {
            logger.error("MapUtil.objToMap error... ", e);
        }

        return map;
    }

    public static <T> MultiValueMap<String, Object> objToMultiValueMap(T obj) {
        if (obj == null) return null;

        MultiValueMap<String, Object> map = new LinkedMultiValueMap();
        BeanInfo beanInfo = null;
        try {
            beanInfo = Introspector.getBeanInfo(obj.getClass());
            PropertyDescriptor[] propertyDescriptors = beanInfo.getPropertyDescriptors();
            for (PropertyDescriptor property : propertyDescriptors) {
                String key = property.getName();
                if (key.compareToIgnoreCase("class") == 0) {
                    continue;
                }
                Method getter = property.getReadMethod();
                Object value = getter != null ? getter.invoke(obj) : null;
                map.add(key, value);
            }
        } catch (Exception e) {
            logger.error("MapUtil.MultiValueMap error... ", e);
        }

        return map;
    }

    public static <T> T mapToObject(Map map, Class<? extends T> beanClass) {
        if (null == map || map.size() == 0) return null;
        try {
            T obj = (T) beanClass.newInstance();
            BeanInfo beanInfo = Introspector.getBeanInfo(obj.getClass());
            PropertyDescriptor[] propertyDescriptors = beanInfo.getPropertyDescriptors();
            for (PropertyDescriptor property : propertyDescriptors) {
                Method setter = property.getWriteMethod();
                if (setter != null) {
                    Object propertyValue = map.get(property.getName());
                    if (propertyValue != null) {
                        setter.invoke(obj, praser(setter, propertyValue));
                    }
                }
            }
            return obj;
        } catch (Exception e) {
            logger.error("MapUtil.objToMap error... ", e);
        }

        return null;
    }

    private static Object praser(Method setter, Object value) {
        Class<?> cls = setter.getParameterTypes()[0];
        if (value instanceof String && cls != String.class) {
            if (StringUtils.isEmpty(value.toString())) {
                return null;
            }
        }

        if (cls.equals(Date.class)) {
            return new Date(Long.parseLong(value.toString()));
        } else if (cls == byte.class || cls == Byte.class) {
            return Byte.parseByte(value.toString());
        } else if (cls == int.class || cls == Integer.class) {
            return Integer.parseInt(value.toString());
        } else if (cls == long.class || cls == Long.class) {
            return Long.parseLong(value.toString());
        } else if (cls == boolean.class || cls == Boolean.class) {
            return Boolean.parseBoolean(value.toString());
        } else if (cls == String.class) {
            String stringValue = value.toString();
            if (stringValue.startsWith("\"") && stringValue.endsWith("\"")) {
                return stringValue.substring(1, stringValue.length() - 1);
            }
        }
        return value;
    }
}
